package com.hmc.modules.sjfx.controller.hgsjfx;

import com.hmc.common.utils.Result;
import com.hmc.modules.sjfx.dto.hgsjfx.YsTsDTO;
import com.hmc.modules.sjfx.service.lashent.LashentService;
import com.hmc.modules.sjfx.util.NormalDistributionUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.apache.commons.math3.stat.regression.RegressionResults;
import org.apache.commons.math3.stat.regression.SimpleRegression;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 原料屈服强度 ys 和钢管抗拉强度 ts 回归分析,ts = a * ys + b
 */
@AllArgsConstructor
@RestController
@RequestMapping("hfsjfx/ysts")
@Tag(name = "原料屈服强度 ys 和钢管抗拉强度 ts 回归分析")
public class YsTsController {
    @Autowired
    private LashentService lashentService;

    /**
     * 获取 钢管 屈服强度和抗拉强度分布，和曲线拟合数据
     */
    @GetMapping("getysts")
    @Operation(summary = "获取 钢管 屈服强度和抗拉强度")
    public Result<Map<String, Object>> getGgQfAndKl() {
        ArrayList<YsTsDTO> ysTs =lashentService.getGgYsTs();
        ArrayList<Double[]> data = getToArray(ysTs);

        SimpleRegression sr = getSimpleRegression(ysTs);

        double a = sr.getSlope(); // 斜率
        double b = sr.getIntercept(); // 截距

        int max = (int) NormalDistributionUtil.getMax(getYsToList(ysTs));

        ArrayList<Double[]> lineData = getLineData(max,a, b);

        Map<String, Object> map = new HashMap<>();
        map.put("data", data);
        map.put("linedata", lineData);

        return new Result<Map<String, Object>>().ok(map);
    }

    /**
     * 获取 斜率 截距 相关系数 回归平方 残差平方和 总平方和
     */
    @GetMapping("getystsinfo")
    @Operation(summary = "获取 斜率 截距 相关系数 回归平方 残差平方和 总平方和")
    public Result<Map<String, String>> getGgQfAndKlInfo() {
        ArrayList<YsTsDTO> ysTs =lashentService.getGgYsTs();

        SimpleRegression sr = getSimpleRegression(ysTs);

        double slope = sr.getSlope(); // 斜率
        double intercept = sr.getIntercept(); // 截距
        double r = sr.getR();  // 相关系数
        double rSquare = sr.getRSquare(); // 回归平方
        double slopeSquare =  sr.getSumSquaredErrors(); // 残差平方和
        double totalSumSquares = sr.getTotalSumSquares(); // 总平方和

        System.out.printf("y = %.6fx + %.4f%n", slope, intercept);
        System.out.printf("r = %.6f%n", r);
        System.out.printf("r2 = %.6f%n", rSquare);
        System.out.printf("EV = %.5f%n", totalSumSquares - slopeSquare);
        System.out.printf("UV = %.4f%n", slopeSquare);
        System.out.printf("TV = %.3f%n", totalSumSquares);

        Map<String, String> map = new HashMap<>();
        map.put("gs", "公式: y = "+slope+"x + "+ intercept);
        map.put("r", "相关系数: "+r);
        map.put("rSquare", "回归平方: "+rSquare);
        map.put("slopeSquare", "残差平方和: "+slopeSquare);
        map.put("totalSumSquares", "总平方和: "+totalSumSquares);

        return new Result<Map<String, String>>().ok(map);
    }

    /**
     * 转换成n行2列的数组
     */
    private ArrayList<Double[]> getToArray(ArrayList<YsTsDTO> ysTs) {
        ArrayList<Double[]> array = new ArrayList<Double[]>();
        for (int i = 0; i < ysTs.size(); i++) {
            Double[] data = new Double[2];
            data[0] = ysTs.get(i).getYs();
            data[1] = ysTs.get(i).getTs();
            array.add(data);
        }
        return array;
    }

    /**
     * 使用一个自变量估计普通最小二乘回归模型。
     * SimpleRegression
     */
    private SimpleRegression getSimpleRegression(ArrayList<YsTsDTO> ysTs) {
        SimpleRegression simpleRegression = new SimpleRegression();
        for (int i = 0; i < ysTs.size(); i++) {
            simpleRegression.addData(ysTs.get(i).getYs(), ysTs.get(i).getTs());
        }
        return simpleRegression;
    }

    /**
     * 已知直线的斜率（m）和截距（b），直线方程通常表示为 y = mx + b
     * 根据直线方程，选择一个合适的x值范围（例如，根据图表的x轴范围），并计算对应的y值。这样可以得到一系列(x, y)数据点
     */
    private ArrayList<Double[]> getLineData(int max,double m, double b) {
        ArrayList<Double[]> array = new ArrayList<Double[]>();

        for (int i = 0; i < max; i++) {
            Double[] data = new Double[2];
            data[0] = (double) i;
            data[1] = m * i + b;
            array.add(data);
        }
        return array;
    }

    /**
     * ArrayList<YsTsDTO> ysTs 转换  List<Double>
     */
    private ArrayList<Double> getYsToList(ArrayList<YsTsDTO> ysTs) {
        ArrayList<Double> array = new ArrayList<Double>();
        for (int i = 0; i < ysTs.size(); i++) {
            array.add(ysTs.get(i).getYs());
        }
        return array;
    }
}
